package cn.lg.soar.mvc.config;

import cn.lg.soar.common.util.current.CurrentThreadContext;
import cn.lg.soar.common.util.current.CurrentUser;
import cn.lg.soar.common.util.current.ICurrentUser;
import cn.lg.soar.common.util.current.ThreadLocalHolder;
import cn.lg.soar.common.util.jackson.JacksonUtil;
import cn.lg.soar.mvc.util.ServletUtils;
import org.slf4j.MDC;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;

/**
 * 当前用户过滤器（主要拥于清除当前用户，释放内存）
 * @author luguoxiang
 * 开源项目：https://gitee.com/lgx1992/lg-soar 求star！请给我star！请帮我点个star！
 */
@Configuration
public class CurrentUserHolderConfig {

    private final static Set<ThreadLocal<?>> THREAD_LOCALS = new HashSet<>();

    @Bean
    public FilterRegistrationBean<Filter> currentUserHolderFilterBean() {
        FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>();
        registration.setFilter(new HandlerFilter());
        registration.addUrlPatterns("/*");
        registration.setName("currentUserHolderFilter");
        registration.setOrder(Ordered.HIGHEST_PRECEDENCE + 10);
        return registration;
    }

    public static class HandlerFilter implements Filter {
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            String requestId = UUID.randomUUID().toString();
            MDC.put("REQUEST_ID", requestId);
            ((HttpServletResponse) servletResponse).addHeader("REQUEST-ID", requestId);
            filterChain.doFilter(servletRequest, servletResponse);
            // 清除ThreadLocal，释放内存
            ThreadLocalHolder.removeCurrentUser();
            CurrentThreadContext.clear();
            THREAD_LOCALS.forEach(ThreadLocal::remove);
            MDC.remove("REQUEST_ID");
        }
    }

    static {
        // 获取当前用户
        ThreadLocalHolder.setCurrentUserThreadLocal(ThreadLocal.withInitial(() -> {
            HttpServletRequest request = ServletUtils.getRequest();
            String header = request.getHeader(CurrentUser.USER_KEY);
            if (header != null) {
                return JacksonUtil.fromJson(header, CurrentUser.class);
            }
            Object data = request.getAttribute(CurrentUser.USER_KEY);
            if (data == null) {
                return null;
            }
            return (ICurrentUser) data;
        }));
        // 获取资源
        ThreadLocalHolder.setResourceThreadLocal(ThreadLocal.withInitial(() -> {
            HttpServletRequest request = ServletUtils.getRequest();
            return request.getMethod().toUpperCase() + request.getServletPath();
        }));
    }

}
